package toolz;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Vector;

public class IMS_CSV_File {

    private File file;                      //Complete File
    private Timestamp date;                 //Date of Measurement
    private double[] scaleK0Inv;   //1/K0 Axis-Values
    private double[] scaleRT;              //Retentiontime Axis-Values in seconds
    private double[] scaleDT;
    private double[][] map;                //Signal intensity matrix in volt
    private HashMap<String, String> header; //additional MetaData in a Hashmap

    public IMS_CSV_File() {
        file = null;
        date = null;
        header = new HashMap<String, String>();
        map = null;
        scaleK0Inv = null;
        scaleRT = null;
    }

    public IMS_CSV_File(File f) {
        file = f;
        date = null;
        header = new HashMap<String, String>();
        map = null;
        scaleK0Inv = null;
        scaleRT = null;
        importFromFile();
    }

    private void importFromFile() {
        //only permitted ending .csv
        String path = file.getAbsolutePath();

        Vector<double[]> data = new Vector<double[]>();
        if (path.endsWith(".csv")) {
            boolean ascii = true; //if false -> ascii rotiert
            try {
                BufferedReader in = new BufferedReader(new FileReader(file));
                String line;

                while ((line = in.readLine()) != null) {
                    if (line.startsWith("#,")) { //MetaData
                        String[] token = line.split(",");
                        if (token.length >= 3) {
                            String key = token[1];
                            header.put(key, token[2]);
                        }
                    } else { //Data
                        String split = ", ";
                        if (line.length() > 1) {
                            if (line.indexOf(", ") < 0) {
                                split = ",";
                            }
                            String[] token = line.split(split);
                            if (token[1].equals("tR")) {
                                ascii = false; //ascii rotiert
                            }
                            double[] values = new double[token.length];
                            for (int i = 0; i < token.length; i++) {
                                double v;
                                try {
                                    v = Double.parseDouble(token[i]);
                                } catch (Exception e) {
                                    v = 0;
                                }
                                values[i] = v;
                            }
                            data.add(values);
                        }
                    }
                }
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            String dsf = file.getName().split("_")[1];
            GregorianCalendar calf = new GregorianCalendar();
            int yyyy = Integer.parseInt(dsf.substring(0, 2)) + 2000;
            int mm = Integer.parseInt(dsf.substring(2, 4)) - 1;
            int dd = Integer.parseInt(dsf.substring(4, 6));
            int hh = Integer.parseInt(dsf.substring(6, 8));
            int min = Integer.parseInt(dsf.substring(8));
            calf.set(yyyy, mm, dd, hh, min, 0);
            //System.out.println("FileTime: "+IMSUtil.getTimeDateString(calf.getTimeInMillis()));
            date = new Timestamp(calf.getTimeInMillis());
            //System.out.println("date="+date+" -> "+IMSUtil.getTimeDateString(date));

            double corr = Double.parseDouble(header.get("tD  (RIP corr.) / ms"));
            double signalFact = Double.parseDouble(header.get("V / signal unit"));
            double baseline_v = 0.0;
            try {
                baseline_v = Double.parseDouble(header.get("baseline / V"));
            } catch (Exception e) {
                baseline_v = 5.0;
            }
            baseline_v = Math.abs(baseline_v - 5.0); //nullline
            if (header.get("polarity").equals("positive")) {
                signalFact *= -1.0;
            }

            int resDT = 0;
            int resRT = 0;
            try {
                resDT = Integer.parseInt(header.get("no. of data points per spectra"));
            } catch (Exception ex) {
                System.out.println("Error in Header at: no. of data points per spectra");
            }
            try {
                resRT = Integer.parseInt(header.get("no. of spectra"));
            } catch (Exception ex) {
                System.out.println("Error in Header at: no. of spectra");
            }

            double[] dt, rt, normDT;
            double[][] m;

            if (ascii) {
                //System.out.println("ASCII");
                //ASCII (nicht rotiert)
                if (resRT == 0) {
                    resRT = data.size() - 2;
                }
                if (resDT == 0) {
                    resDT = data.get(2).length - 2;
                }
                dt = new double[resDT];                 //in ms
                scaleK0Inv = new double[resDT];         //in 1/k0
                normDT = new double[resDT];     //in dt/posRIP
                rt = new double[resRT];                 //in s
                m = new double[resDT][resRT];

                double[] val = data.get(0);
                for (int j = 0; j < resDT; j++) {
                    scaleK0Inv[j] = val[j + 2];
                }
                val = data.get(1);
                for (int j = 0; j < resDT; j++) {
                    dt[j] = val[j + 2];
                    normDT[j] = dt[j] / corr;
                }

                for (int i = 0; i < resRT; i++) {
                    rt[i] = data.get(i + 2)[0];
                }

                for (int i = 0; i < resRT; i++) {
                    val = data.get(i + 2);
                    for (int j = 0; j < resDT; j++) {
                        //m[j][i] = val[j+2]*signalFact + 5.0-baseline_v;//+baseline_v*signalFact;
                        m[j][i] = val[j + 2] * signalFact + baseline_v;
                    }
                }
            //-- end ASCII

            } else {
                //ASCII rotiert:
                //System.out.println("ASCII rotiert");
                //Scales and Intensity Matrix
                //System.out.println("real resDT="+(data.size()-2)+"  resRT="+(data.get(2).length-2));
                if (resDT == 0) {
                    resDT = data.size() - 2;
                }
                if (resRT == 0) {
                    resRT = data.get(2).length - 2;
                }

                dt = new double[resDT];                 //in ms
                scaleK0Inv = new double[resDT];         //in 1/k0
                normDT = new double[resDT];     //in scaleDT/posRIP
                rt = new double[resRT];                 //in s
                m = new double[resDT][resRT];

                for (int i = 0; i < resDT; i++) {
                    try {
                        dt[i] = data.get(i + 2)[1];
                        scaleK0Inv[i] =  data.get(i + 2)[0];// data.get(i + 2)[0];
                        normDT[i] = dt[i] / corr;
                    } catch (Exception ex) {
                        dt[i] = dt[i - 1] + dt[i - 1] - dt[i - 2];
                        scaleK0Inv[i] = scaleK0Inv[i - 1] + scaleK0Inv[i - 1] - scaleK0Inv[i - 2];
                        normDT[i] = dt[i] / corr;
                    //System.out.println("Missing data at dt="+i);
                    }
                }

                double[] val = data.get(0);
                for (int j = 0; j < resRT; j++) {
                    try {
                        rt[j] = val[j + 2];
                    } catch (Exception ex) {
                        rt[j] = rt[j - 1] + rt[j - 1] - rt[j - 2];
                    //System.out.println("Missing data at rt="+j);
                    }
                }

                for (int i = 0; i < resDT; i++) {
                    try {
                        val = data.get(i + 2);
                    } catch (Exception ex) {
                        val = null;
                    }
                    for (int j = 0; j < resRT; j++) {
                        //m[i][j] = val[j+2]*signalFact+baseline_v;
                        //m[i][j] = val[j+2]*signalFact + 5.0-baseline_v;//+baseline_v*signalFact;
                        try {
                            m[i][j] = val[j + 2] * signalFact + baseline_v;
                        } catch (Exception ex) {
                            m[i][j] = baseline_v;
                        //System.out.println("Missing signal at i="+i+" j="+j);//+" val.len = "+val.length+" resRT = "+resRT+" resDT = "+resDT);
                        }
                    }
                }
            //-- end ASCII rotiert
            }

            map = m;
            scaleRT = rt;
            scaleDT = dt;

            //header toleranz
            String mccTemp = header.get("pre-separation T / deg C");
            try {
                if (mccTemp.endsWith("�C")) {
                    header.put("pre-separation T / deg C", mccTemp.substring(0, mccTemp.length() - 2).trim());
                }
            } catch (Exception ex) {
                System.out.println("Error while parsing \"pre-separation T / deg C\"");
                ex.printStackTrace();
            }

        } else {
            System.out.println("Wrong file format");
        }
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public HashMap<String, String> getHeader() {
        return header;
    }

    public void setHeader(HashMap<String, String> header) {
        this.header = header;
    }

    public double[][] getMap() {
        return map;
    }

    public void setMap(double[][] map) {
        this.map = map;
    }

    public double[] getScaleK0Inv() {
        return scaleK0Inv;
    }

    public double[] getScaleDT(){
        return this.scaleDT;
    }

    public void setScaleK0Inv(double[] scaleK0Inv) {
        this.scaleK0Inv = scaleK0Inv;
    }

    public double[] getScaleRT() {
        return scaleRT;
    }

    public void setScaleRT(double[] scaleRT) {
        this.scaleRT = scaleRT;
    }

    public Timestamp getDate() {
        return date;
    }

    public void setDate(Timestamp date) {
        this.date = date;
    }
}